/*
 * ServerLauncher.java
 *
 * Written by: 
 * Czahrien <czahrien@gmail.com>
 * 
 * Version 6.0
 *
 * Licensing:
 * I am not going to be a stickler about licensing and all that jazz. Just be 
 * sure to give credit to me where credit is due and we can all get along like
 * grown-ups. Okay?
 *
 * Description:
 * This is a wrapper meant for Notch's Survival Multiplayer server, version 
 * 0.1.0. It is not guaranteed to work well with later versions.
 *
 * While this code is far from my best work, it does demonstrate an approach to
 * take to wrap a server of this type. Most of this is hastily thrown together
 * and as a result I use a lot of static data members.
 */

import java.io.*;
import java.util.*;
import java.util.regex.*;
import java.text.SimpleDateFormat;
import java.text.DateFormat;
import java.text.ParseException;


public class ServerLauncher extends Thread {
	
	public static final int TRANSACTION_RESULT_OK = 0;
	public static final int TRANSACTION_RESULT_USER_DONT_EXISTS = 1;
	public static final int TRANSACTION_RESULT_NOT_ENOUGH_MONEY = 2;
	public static final int TRANSACTION_RESULT_NEGATIVE_MONEY = 3;
	public static final int TRANSACTION_RESULT_SAME_USER = 4;
	
	public static final int TELEPORT_PRICE = 100;
	public static final int LOTTERY_TICKET_PRICE = 150;	
	public static final int NUM_TICKETS_PER_DAY = 3;	
	
    public static final int P_SUPERADMIN = 3;
    public static final int P_ADMIN = 2;
    public static final int P_TRUSTED = 1;
    public static final int P_ALLOWED = 0;
    public static final int P_BANNED = -1;

	// The wrapped process
    private Process myProcess;
	
    // Input/Output Readers/Writers for the process.
    private BufferedReader myErrReader;
    private BufferedReader myInReader;
    private PrintWriter myWriter;
	
    // Variables used for run() and other functions.
    private boolean keep_going;
    private int myPlayerCount;
    private String connectedPlayers;
    private String ban_command;
    private String list_command;
    private Date startTime;
    // TODO: Implement us
    private String votekickName;
    private Date votekickDate;
    private int votekickVotes;
    private boolean isVoteban;
	
    // Maps and sets
    private HashMap<String,Integer> permissions;
    private HashMap<String,Integer> items;
    private HashSet<String> blacklist;
    private HashMap<String,ArrayList<Integer>> kits;
    private HashMap<String,String> ipassoc;
    private HashSet<String> ipbans;
    private HashMap<String,Integer> money;
	private HashMap<String,Integer> lotteryPlayTime;
	ArrayList<Item> buyableItems;
	
	// data registrata nel file lotteryPlayTime
	Date lotteryFileDate;
    // TODO: Implement me
    private HashMap<String,Date> playerLoginTimes;
	
    // Property Values
    private int myPlayerCap;
    private int myRAMUse;
    private boolean isPlayerWhiteList;
    private boolean isItemWhiteList;
    private boolean isFun;
    private boolean autoSave;
    private Date lastSave;
	private SimpleDateFormat dateFormat;
	
	Random randomNumberGenerator;
	
    public static void main( String[] args ) {
        try {
            // Create the ServerLauncher
            ServerLauncher o = new ServerLauncher();
            o.start();
            o.join();
        } catch( Exception e ) {
            e.printStackTrace();
        }
    }

    public ServerLauncher() {
        super();
		dateFormat = new SimpleDateFormat("yyyy.MM.dd HH:mm");
        startTime = new Date();
        lastSave = startTime;
		randomNumberGenerator = new Random();
        try {
            FileInputStream fis = new FileInputStream( "ServerLauncher.properties" );
            Properties p = new Properties();
            p.load( fis );
            String value = p.getProperty( "fun" );
            if( value != null && value.equalsIgnoreCase( "true" ) ) {
                isFun = true;
                System.out.println( "Fun mode is enabled." );
            } else {
                isFun = false;
                System.out.println( "Fun mode is disabled." );
            }
            value = p.getProperty( "itemwhitelist" );
            if( value != null && value.equalsIgnoreCase( "true" ) ) {
                isItemWhiteList = true;
            } else {
                isItemWhiteList = false;
            }
            value = p.getProperty( "playerwhitelist" );
            if( value != null && value.equalsIgnoreCase( "true" ) ) {
                isPlayerWhiteList = true;
            } else {
                isPlayerWhiteList = false;
            }
            value = p.getProperty( "playercap" );
            if( value != null ) {
                try {
                    myPlayerCap = Integer.parseInt( value );
                    System.out.println( "Setting player cap to " + myPlayerCap + "." );
                } catch( NumberFormatException e ) {
                    System.err.println( "ERROR: Invalid number for player cap." );
                    myPlayerCap = -1;
                }
            } else {
                myPlayerCap = -1;
            }
            value = p.getProperty( "ram" );
            if( value != null ) {
                try {
                    myRAMUse = Integer.parseInt( value );
                    System.out.println( "Setting ram use to " + value + "mb." ); 
                } catch( NumberFormatException e ) {
                    System.err.println( "ERROR: Invalid amount of ram." );
                    myRAMUse = 1024;
                }
            } else {
                myRAMUse = 1024;
            }
            value = p.getProperty( "autosave" );
            if( value != null && value.equalsIgnoreCase( "false" ) ) {
                autoSave = false;
            } else {
                autoSave = true;
            }
        } catch( IOException e ) {
            if( e instanceof FileNotFoundException ) {
                System.err.println( "ERROR: Cannot open ServerLauncher.properties" );
                Properties p = new Properties();
                p.setProperty( "fun", "false" );
                p.setProperty( "itemwhitelist", "true" );
                p.setProperty( "playerwhitelist", "false" );
                p.setProperty( "playercap", "-1" );
                p.setProperty( "ram", "1024" );
                p.setProperty( "autosave", "true" );
                try { 
                    p.store( new FileOutputStream( "ServerLauncher.properties" ), "Properties for ServerLauncher" );
                } catch( IOException f ) {}
            }

            else {
                System.err.println( "ERROR: ServerLauncher.properties is of an invalid format." );
            }
            Properties p = new Properties();

            isFun = false;
            isPlayerWhiteList = true;
            isItemWhiteList = false;
            myPlayerCap = -1;
            myRAMUse = 1024;
            autoSave = true;
        }
        // Start the server process
        try {
            myProcess = Runtime.getRuntime().exec( "java -Xms" + myRAMUse + "m -Xmx" + myRAMUse + "m -jar minecraft_server.jar nogui" );
        } catch( IOException e ) {
            e.printStackTrace();
            System.err.println( "Could not run the server." );
            System.exit(1);
        }
        // Reader of stderr for the server
        myInReader = new BufferedReader( new InputStreamReader( myProcess.getInputStream() ) );
        // Reader of stdout for the server
        myErrReader = new BufferedReader( new InputStreamReader( myProcess.getErrorStream() ) );
        // Writer for stdin of the server
        myWriter = new PrintWriter( new OutputStreamWriter( myProcess.getOutputStream() ), true );        

        loadLists();

        keep_going = true;
        myPlayerCount = 0;
        connectedPlayers = "";

        ban_command = "ban";
        if( isPlayerWhiteList ) {
            ban_command = "allow";
        }

        list_command = "blacklist";
        if( isItemWhiteList ) {
            list_command = "whitelist";
        }
    }

    public void run() {
        try {
            String line = "";
            // Patterns for regex pattern recognition. They are thorough so
            // sneaky players cannot break it by saying [INFO] and all that jazz.
            Pattern[] patterns = new Pattern[4];
            String colors = "(?:[^\\p{Alnum}^\\p{Digit}^\\055_^\\.]\\p{Alnum}){0,1}";
            String beginning = "^\\p{Digit}{4}-\\p{Digit}{2}-\\p{Digit}{2} \\p{Digit}{2}:\\p{Digit}{2}:\\p{Digit}{2} \\[INFO\\] ";
            patterns[0] = Pattern.compile( beginning +
                    "[\\[<]" + colors + "([\\055\\w\\.]*)" + colors + "[>\\]] #([\\p{Alpha}\\p{Digit}\\p{Punct} ]*)" );
            patterns[1] = Pattern.compile( beginning +
                    "(.*) \\[/(\\p{Digit}{1,3}.\\p{Digit}{1,3}.\\p{Digit}{1,3}.\\p{Digit}{1,3}):\\p{Digit}*\\] logged in" );
            patterns[2] = Pattern.compile( beginning +
                    "Connected players: ([\\055\\w\\., ]*)" );
            patterns[3] = Pattern.compile( beginning +
                    "Giving [\\w\\055\\.]* some \\p{Digit}{1,4}" );


            BufferedReader input = new BufferedReader( new InputStreamReader( System.in ) );
            while( keep_going ) {
				resetLotteryPlayTimeIfNeeded();
                Date d = new Date();
                long offset = d.getTime() - lastSave.getTime();
                // autosave every ten minutes
                if( offset / 1000 / 60 >= 10 ) {
                    lastSave = new Date();
                    saveLists();
                }

                line = "";
                // Loop while the server is still running.
                while( input.ready() && !line.equals("stop") ) {
                    line = input.readLine();
                    myWriter.println( line );
                }

                if( line.equals( "stop" ) ) {
                    keep_going = false;
                    break;
                }

                // This loop handles stdout from the server.
                while( myInReader.ready() ) {
                    line = myInReader.readLine();
                    System.out.println( "O: " + line );
                    // Currently the wrapper is using the server's "Player count: " messages to keep count of the players.
                    // This is a temporary measure until keeping track of the players in-game is perfect.
                    if( line.startsWith( "Player count: " ) ) {
                        myWriter.println( "list" );
                        try {
                            myPlayerCount = Integer.parseInt( line.split( ": " )[1] );
                        } catch( NumberFormatException e ) {
                            myPlayerCount = -1;
                        }
                        String cap = "";
                        if( myPlayerCap > 0 ) {
                            cap += "/" + myPlayerCap;
                        }
                        if( myPlayerCap >= myPlayerCount ) {
                            myWriter.println( "There are currently " + myPlayerCount + cap + " players on the server." );
                        }
                    }
                }

                // This loop handles stderr from the server.
                while( myErrReader.ready() ) {
                    line = myErrReader.readLine();
                    if( myWriter != null ) {
                        // Create a pattern matcher for the line read in.
                        Matcher[] m = new Matcher[patterns.length];
                        for( int i = 0; i < patterns.length; i++ ) {
                            m[i] = patterns[i].matcher( line );
                        }

                        // m[3] prevents give message spam.
                        // TODO: When give fails because of an invalid item-id, spam happens. Fix.
                        if( !m[3].matches() ) {
                            System.out.println( "E: " + line );
                        }
                        // m[0] matches chat messages beginning with a pound sign.
                        if( m[0].matches() ) {
                            String name = m[0].group(1);
                            String[] parts = m[0].group(2).split( "\\s+" );
                            // #summon <item-id> <count> / #summon <kit>
                            if( parts.length >= 2 && ( parts[0].equalsIgnoreCase( "summon" ) || parts[0].equalsIgnoreCase( "s" ) ) 
                                  && isAdmin(name) /*  && ( isFun || isTrusted(name)*/ ) {
                                int times = 1;
                                // If there are >= 3 parts there may be an item count count.
                                if( parts.length >= 3 ) {
                                    try { 
                                        times = Integer.parseInt( parts[2] );
                                    } catch( Exception e ) {
                                    }
                                    // A reasonable cap is 64.
                                    if( times > 64 ) {
                                        times = 64;
                                    }
                                }

                                try {
                                    int id = Integer.parseInt( parts[1] );
                                    parts[1] = "" + id;
                                    // Admins are not affected by blacklisting.
                                    // Trusted players are if fun mode is off.
                                    if( !isAdmin(name) &&  
                                            !( isTrusted(name) && isFun ) && 
                                            !( !isItemWhiteList ^ blacklist.contains( parts[1] ) ) ) {
                                        System.out.println( name + " tried to summon something blacklisted." );
                                    } else {
                                        System.out.println( "Summoning " + times + " of " + id + " for " + name );
                                        for( int i = 0; i < times; i++ ) {
                                            myWriter.println( "give " + name + " " + id );
                                        }
                                    }
                                } catch( NumberFormatException e ) {
                                    ArrayList<Integer> ids = kits.get( parts[1].toLowerCase() );
                                    if( ids != null ) {
                                        for( Integer i : ids ) {
                                            give( name, i );
                                        }
                                    }
                                }
                                // #give <player> <item> <count> // #give <player> <kit>
                            } else if( parts[0].equalsIgnoreCase( "give" ) 
                                    && parts.length >= 3 && isAdmin(name) ) {
                                int times = 1;
                                // If there are >= 4 parts there may be an item count count.
                                if( parts.length >= 4 ) {
                                    try { 
                                        times = Integer.parseInt( parts[3] );
                                    } catch( Exception e ) {
                                    }
                                    // A reasonable cap is 64.
                                    if( times > 256 ) {
                                        times = 256;
                                    }
                                }

                                try {
                                    int id = Integer.parseInt( parts[2] );
                                    give( parts[1], id, times );
                                } catch( NumberFormatException e ) {
                                    give( parts[1], parts[2] );
                                }
                                // #stop
                            } 
							// MONEY SYSTEM
							
							else if( parts[0].equalsIgnoreCase( "money" ) ) {
                                if( parts.length == 1 ) {

                                    Integer i = money.get( name.toLowerCase() );
                                    if( i == null ) {
                                        i = 0;
                                    }
                                    playerPrint( name + " haves " + i + " money." );
                               /* } else if( isAdmin(name) ) {
                                    Integer i = money.get( parts[1].toLowerCase() );
                                    if( i == null ) {
                                        i = 0;
                                    }
                                    if( parts.length > 2 ) {
                                        try {
                                            money.put( parts[1].toLowerCase(), i + Integer.parseInt( parts[2] ) );
                                            i = money.get( parts[1].toLowerCase() );
                                            playerPrint( parts[1] + " now has " + i + " money." );
                                        } catch( NumberFormatException e ) {}
                                    } else {
                                        playerPrint( parts[1] + " has " + i + " money." );
                                    }
*/
                                }
                            } 
							
							else if ( parts[0].equalsIgnoreCase( "pay" ) && parts.length > 2 ) {
								try {
									int money = Integer.parseInt( parts[2] );
									int transactionResult = moneyTransaction( name.toLowerCase(), parts[1].toLowerCase(), money );
									if (transactionResult == TRANSACTION_RESULT_OK) {
										playerPrint( name + " has payed " + money + " to " +parts[1] );
									} else if (transactionResult == TRANSACTION_RESULT_USER_DONT_EXISTS) {
										playerPrint( name + " can't pay: wrong username (" + parts[1] +")");
									} else if (transactionResult == TRANSACTION_RESULT_NOT_ENOUGH_MONEY) {
										playerPrint( name + " doesn't have enough money to pay " + parts[1]);
									} else if (transactionResult == TRANSACTION_RESULT_NEGATIVE_MONEY) {
										playerPrint( name + " can't pay: money is not > 0!");
									} else if (transactionResult == TRANSACTION_RESULT_SAME_USER) {
										playerPrint("You idiot -_-");
									}
								} catch( NumberFormatException e ) {}
							} else if ( parts[0].equalsIgnoreCase( "jackpot" ) ) {
								int jp = getMoney("server");
								playerPrint("Jackpot is currently: " + jp + " moneys!");
							} else if ( parts[0].equalsIgnoreCase( "playLottery" ) ) {
								playLottery( name );
							} else if ( parts[0].equalsIgnoreCase( "lotteryTimeLeft" ) ) {
								int minutes = minutesBeforeNextJackpotRestart();
								playerPrint( minutes+" minutes left before next lottery restart");
							}
							/*else if ( parts[0].equalsIgnoreCase( "randomtp" ) ) {
								randomTeleport( name );
							}*/
							else if ( parts[0].equalsIgnoreCase( "buy" ) ) {
								if (parts.length > 2) {
									try {
										int num = Integer.parseInt(parts[2]);
										buy(name, parts[1], num);										
									} catch( NumberFormatException e ) {}
								} else if (parts.length > 1) {
									buy(name, parts[1], 1);
								} else {
									listBuyableThings();
								}
							}
							
							else if( parts[0].equalsIgnoreCase( "stop" ) && isAdmin(name) ) {
                                keep_going = false;
                                myWriter.println( "Server is going down!" );
                                myWriter.println( "stop" );
                                // #time
                            } else if( parts[0].equalsIgnoreCase( "time" ) ) {
                                time();
                                // #uptime
                            } else if( parts[0].equalsIgnoreCase( "uptime" ) ) {
                                uptime();
                                // #motd
                            } else if( parts[0].equalsIgnoreCase( "motd" ) ) {
                                printFile("motd.txt");
                                // #rules
                            } else if( parts[0].equalsIgnoreCase( "rules" ) ) {
                                rules();
                            } else if( parts[0].equalsIgnoreCase( "TNT" ) ) {
                                tnt( name );
                            } else if ( parts.length == 2 && parts[0].equalsIgnoreCase( "tp" ) /* && isTrusted(name) */ ) {
								String destination = parts[1].toLowerCase();
								if (name.equalsIgnoreCase(destination)) {
									playerPrint("You idiot -_-");
								} else if (isUserOnline(destination) ) {
									if (getMoney(name) >= TELEPORT_PRICE) {
										teleport( name, destination);
										buyFromServer(name, TELEPORT_PRICE);
										playerPrint( name + " lost 100 moneys teleporting to "+ destination);
									} else {
										playerPrint( name + " doesn't have enough money to teleport");
									}
								} else {
									
								}								
							} else if( parts[0].equalsIgnoreCase( "help" ) ) {
                                help( name ); 
							} else if ( parts[0].equalsIgnoreCase( "helpmoney" ) ) {
								printFile("helpmoney.txt");
							   // #reload
                            } else if ( parts[0].equalsIgnoreCase( "helpadmin" ) ) {
								printFile("helpadmin.txt");
								// #reload
                            } else if ( parts[0].equalsIgnoreCase( "helpgeneral" ) ) {
								printFile("helpgeneral.txt");
								// #reload
                            } else if ( parts[0].equalsIgnoreCase( "reload" ) && isAdmin(name) ) {
                                loadLists();
                                // #save
                            } else if( parts[0].equalsIgnoreCase( "save" ) && isAdmin(name) ) {
                                saveLists();
                                // #list
                            } else if ( parts[0].equalsIgnoreCase( "list" ) ) {
                                playerList();
                                // #playercap <new cap>
                            } else if( parts.length == 2 && parts[0].equalsIgnoreCase( "playercap" ) && isAdmin( name ) ) {
                                try {
                                    int n = Integer.parseInt( parts[1] ); 
                                    setPlayerCap( n );
                                } catch( NumberFormatException e ) {}
                                // #kick <name>
                            } else if ( parts.length == 2 && parts[0].equalsIgnoreCase( "kick" ) && 
                                    (isAdmin(name) || isTrusted(name)) && !isAdmin(parts[1]) )  {
                                // TODO: rewrite kick to be kick( kicker, kicked )
                                kick(parts[1]);
                                // #ban <name>
                            } else if ( parts.length == 2 && parts[0].equalsIgnoreCase( ban_command ) && 
                                    (isAdmin(name) || isTrusted(name)) ) {
                                ban(name, parts[1]);
                                // #unban <name>
                            } else if ( parts.length == 2 && parts[0].equalsIgnoreCase( "un" + ban_command ) && 
                                    (isAdmin(name) || isTrusted(name)) ) {
                                unban( parts[1] );
                                // #ipban <name or IP>
                            } else if( parts.length == 2 && parts[0].equalsIgnoreCase( "ipban" ) && isAdmin( name ) ) {
                                if( ipban( parts[1] ) ) {
                                    playerPrint( parts[1] + " was IP Banned." ); 
                                }
                            } else if( parts.length >= 1 && parts[0].equalsIgnoreCase( "iplist" ) && isAdmin( name ) ) {
                                boolean online = parts.length == 2 && parts[1].equalsIgnoreCase( "online" );
                                ipList( online );
                                // #admin <name>
                            } else if ( parts.length == 2 && parts[0].equalsIgnoreCase( "admin" ) && 
                                    isAdmin(name) ) {
                                admin( parts[1] );
                                // #unadmin <name>
                            } else if ( parts.length == 2 && parts[0].equalsIgnoreCase( "unadmin" ) && isAdmin(name) ) {
                                unadmin( name, parts[1] );
                                // #blacklist <id>
                            } else if ( parts.length == 2 && parts[0].equalsIgnoreCase( list_command ) && 
                                    isAdmin(name) ) {
                                blacklist.add( parts[1].toLowerCase() );
                                // #unblacklist <id>
                            } else if ( parts.length == 2 && parts[0].equalsIgnoreCase( "un" + list_command ) && 
                                    isAdmin(name) ) {
                                blacklist.remove( parts[1].toLowerCase() );
                                // #trust <id>
                            } else if ( parts.length == 2 && parts[0].equalsIgnoreCase( "trust" ) && 
                                    isAdmin(name) ) {
                                trust( parts[1] );
                                // #untrust <id>
                            } else if ( parts.length == 2 && parts[0].equalsIgnoreCase( "untrust" ) && 
                                    isAdmin(name) ) {
                                untrust( parts[1] );
                                // #fun
                            } else if( parts[0].equalsIgnoreCase( "fun" ) && isAdmin(name) ) {
                                toggleFun();
                            }
                        }
                        else if( m[1].matches() ) {
                            welcome( m[1].group(1), m[1].group(2) );
                        }
                        else if( m[2].matches() ) {
                            connectedPlayers = m[2].group(1);
                        } 
                    }
                }
                sleep( 100 );
            }
            myInReader.close();
            myErrReader.close();
            myWriter.close();
            saveLists();
        } catch( Exception e ) {
            e.printStackTrace();
            keep_going = false;
        }
    }

	public void spawnKit( String user, String toolkit) {
		ArrayList<Integer> ids = kits.get(toolkit);
		if( ids != null ) {
			for( Integer i : ids ) {
				give( user, i );
			}
		}	
	}


    public void welcome( String name, String ip ) {
        ipassoc.put( name.toLowerCase(), ip );
        // TODO: Is 20 good?
        // 20 is too long, 2 is the minimum size. It shall suffice for now.
        Pattern p = Pattern.compile( "[\\p{Alnum}\\055_\\.]{2,20}" );
        Matcher m = p.matcher( name );
		Integer i = money.get( name.toLowerCase() );
        if( !( !isPlayerWhiteList ^ isBanned(name) ) || isIPBanned( ip ) || !m.matches() )  {
            kick( name );
            if( !m.matches() ) {
                ipban( ip );
            }
        }
        else if( !isAdmin(name) && !isTrusted(name) ) {
            if( myPlayerCap > 0 && myPlayerCount > myPlayerCap ) {
                kick( name );
                playerPrint( "Player cap reached, kicking " + name + "." );
            } else {
//                playerPrint( "Welcome, " + name + "!" );
                printFile("motd.txt");
				if (i == null)
					giveMoney(name, 500);
            }
        } else if( isAdmin(name) ) {
			if (i == null)
				giveMoney(name, 5000);
			printFile("motd.txt");
//            playerPrint( "Quick! Everybody hide! " + name + " is an admin!" );
//			spawnKit( name, "toolkit");
//			spawnKit( name, "torches");
		} else if( isTrusted( name ) ) {
			printFile("motd.txt");
			if (i == null)
				giveMoney(name, 1200);
//			playerPrint( "say " + name + " is a pretty trustworthy guy." );
//			spawnKit( name, "toolkit");
//			spawnKit( name, "torches");
        }

    }
	
	public Collection<String> playersListAsCollection () {
		Collection<String> players = Arrays.asList(connectedPlayers.toLowerCase().split( ",\\s+" ));
		return players;
	}

	public String[] playersList () {
		String[] players = connectedPlayers.toLowerCase().split( ",\\s+" );
		return players;
	}
	
	public boolean isUserOnline ( String user) {
		String lowercaseUser = user.toLowerCase();
		Collection<String> players = playersListAsCollection();
		for( String s : players ) {
//			playerPrint( s );
			if (s.equals(lowercaseUser)) {
				return true;
			}
		}
		return false;
	}
	
	public int getMoney( String user) {
		Integer i = money.get( user.toLowerCase() );
		if (i == null)
			return 0;
		return i.intValue();
	}
	
			
	public boolean giveMoney( String user, int moneyQuantity ) {
		Integer mInt = new Integer(moneyQuantity);				
		int userMoney = getMoney(user);
//		if (userMoney < 0)
//			return false;
		money.put( user.toLowerCase(), mInt + userMoney );				
		return true;
	}
	
	// compra qualcosa che costa moneyQuantity dal server
	// I soldi vengono rimossi dall'user e vengono aggiunti al server
	public void buyFromServer( String user, int moneyQuantity) {
		giveMoney(user, -moneyQuantity);
		giveMoney("server", moneyQuantity);
	}
	
	public int moneyTransaction( String fromUser, String toUser, int moneyQuantity ) {
		fromUser = fromUser.toLowerCase();
		toUser = toUser.toLowerCase();
		if (fromUser.equalsIgnoreCase(toUser))
			return TRANSACTION_RESULT_SAME_USER;
		if (moneyQuantity <= 0) {
			return TRANSACTION_RESULT_NEGATIVE_MONEY;
		}
//		playerPrint( "from user:" + fromUser );
//		playerPrint( "to user:" + toUser );
		if (isUserOnline(fromUser) && (isUserOnline(toUser)) ) {
			int totalMoney = getMoney(fromUser);
			if (totalMoney < moneyQuantity)
				return TRANSACTION_RESULT_NOT_ENOUGH_MONEY;
			giveMoney(fromUser, -moneyQuantity);
			giveMoney(toUser, moneyQuantity);
			return TRANSACTION_RESULT_OK;
		} else {
			return TRANSACTION_RESULT_USER_DONT_EXISTS;
		}
	}
	
	public void listBuyableThings () {
		for( int i = 0; i < buyableItems.size(); i++ ) {
			Item item = buyableItems.get(i);
			playerPrint( item.description + ", Price: " + item.price + " money");
			
		}
	}
	
	public Item getItem(String kitDescription) {
		for( int i = 0; i < buyableItems.size(); i++ ) {
			Item item = buyableItems.get(i);
			if (item.description.equalsIgnoreCase(kitDescription) ) {
				return item;
			}
		}
		return null;
	}
	
	public void buy( String user, String kitDescription, int quantity) {
		if (quantity <= 0) {
			playerPrint("Can't buy a negative quantity!");
		}
		Item item = getItem(kitDescription);
		if (item == null) {
			playerPrint("Can't find any item named "+ kitDescription);
			return;
		}
		int price = (item.price * quantity);
		if (getMoney(user) < price ) {
			playerPrint(user + " doesn't have enough money to buy "+quantity+" " +kitDescription);
			return;
		}
		playerPrint(user + " bought "+quantity+" " +kitDescription + " for " +price);
		buyFromServer(user, price);
		for (int i = 0; i < quantity; i++) {
			spawnKit(user, item.kitName);
		}
	}
	
	public void resetLotteryPlayTimeIfNeeded () {
		Date date = new Date();
		int numHours = numHoursBetweenDates(date, lotteryFileDate);
		if (numHours >= 12) {
			lotteryPlayTime.clear();
			lotteryFileDate = new Date();
			saveLists();
		System.err.println("numHoursBetweenDates: "+numHours+" DateNow: "+date.toString()+" DateLastLottery: "+lotteryFileDate.toString());			
			playerPrint("Lottery times are resetted! You can play again now!");
			playerPrint("Good Luck! :-D!");
		}
	}
	
	public int minutesBeforeNextJackpotRestart() {
		Date date = new Date();
		long time1 = date.getTime();
		long time2 = lotteryFileDate.getTime() + (1000 * 60 * 60 * 12);
		return Math.abs((int)( (time2 - time1) / (1000 * 60) ));
	}
	
	public int numHoursBetweenDates (Date date1, Date date2) {
		long time1 = date1.getTime();
		long time2 = date2.getTime();
	//	System.err.println(time2 - time1);		
		return Math.abs((int)( (time2 - time1) / (1000 * 60 * 60)));	
	}
	
	public int numGamesLotteryLeft (String user) {
		Integer i = lotteryPlayTime.get(user.toLowerCase());
		if (i == null) {
			lotteryPlayTime.put(user.toLowerCase(), new Integer(0));
			i = lotteryPlayTime.get(user.toLowerCase());
		}
		return NUM_TICKETS_PER_DAY - i.intValue();
	}
	
	public void incNumGamesLottery (String user) {
	/*	Date date = new Date();
		int numDays = numDaysBetweenDates(date, lotteryFileDate);
		System.err.println("numDaysBetweenDates: "+numDays+" DateNow: "+date.toString()+" DateLastLottery: "+lotteryFileDate.toString());
		if (numDays > 0) {
			resetLotteryPlayTimes();
		}*/
		Integer i = lotteryPlayTime.get(user.toLowerCase());
		lotteryPlayTime.put(user.toLowerCase(), new Integer(i.intValue() + 1) );
	}
	
	public void printLMoneyLeaderboard() {
//		Collection c = money.values();
	}
	
	public void randomTeleport( String user) {
		String [] players = playersList();
		int n = randomNumberGenerator.nextInt(players.length);
		teleport(user, players[n]);
	}
	
	public void playLottery( String user ) {
		if (getMoney("server") < LOTTERY_TICKET_PRICE * 2) {
			playerPrint("Jackpot it's too low (only " + getMoney("server")  + ")");
			return;
		}
		if (numGamesLotteryLeft(user) <= 0) {
//			playerPrint(user + " have played lottery too much for today!");
			int minutes = minutesBeforeNextJackpotRestart();
			playerPrint(user +" need to wait "+ minutes+" minutes before playing again");
			return;
		}
		if (getMoney(user) < LOTTERY_TICKET_PRICE) {
			playerPrint(user + " doesn't have enough money to play lottery!");
			return;
		}
		buyFromServer(user, LOTTERY_TICKET_PRICE);
		int r = randomNumberGenerator.nextInt(100);
		r++;
		int jp = getMoney("server");
		int moneyWon = 0;
		if (r <= 3) {
			moneyWon = jp;
			playerPrint(user + " WON THE ENTIRE JACKPOT! " + moneyWon + " MONEY!");
		} else if (r <= 7) {
			moneyWon = jp / 2;
			playerPrint(user + " WON HALF THE JACKPOT! " + moneyWon + " MONEY!");
		} else if (r <= 18) {
			moneyWon = jp / 4;
			playerPrint(user + " WON 1/4 OF THE JACKPOT! " + moneyWon + " MONEY!");
		} else if (r <= 19) {
			playerPrint(user + " WON SOME LAVA! ");
			give(user, 10);
		} else if (r <= 21) {
			playerPrint(user + " WON SOME WATER! ");
			give(user, 8);
		}else if (r <= 22) {
			playerPrint(user + " WON A TNT! ");
			give(user, 46);
		} else if (r <= 23) {
			playerPrint(user + " WON A DIAMOND TOOLKIT! ");
			spawnKit(user, "dtoolkit");
		} else if (r <= 24) {
			playerPrint(user + " WON A DIAMOND ARMOR! ");
			spawnKit(user, "armor");
		} else if (r <= 25) {
			playerPrint(" NEGATIVE PRIZE! "+user +" LOST 1000 MONEY O_O! ");
			buyFromServer(user, 1000);
		} else if (r <= 26) {
			playerPrint(user + " WON A CACTUS! ");
			give(user, 81);
		} else if (r <= 27) {
			playerPrint(user + " WON EXCALIBUR! ");
			give(user, 283);
		} else if (r <= 28) {
			playerPrint(user + " WON A TORCH! ");
			give(user, 50);
		} else if (r <= 29) {
			playerPrint(user + " WON A LIBRARY! ");
			give(user, 47);
		} else if (r <= 30) {
			playerPrint(user + " WON A BOOK! ");
			give(user, 340);
		} else if (r <= 31) {
			playerPrint(user + " WON SOME REDWIRE! ");
			give(user, 55);
			give(user, 55);
			give(user, 55);
			give(user, 55);
			give(user, 55);
			give(user, 55);
			give(user, 55);
			give(user, 55);
			give(user, 55);
			give(user, 55);
			give(user, 55);
			give(user, 55);
		} else if (r <= 32) {
			playerPrint(user + " WON A DIAMOND! ");
			give(user, 264);
		} else if (r <= 33) {
			playerPrint(user + " WON A .. wooden pickaxe -_- ");
			give(user, 270);
		} else if (r <= 34) {
			playerPrint(user + " WON A PAINTING! ");
			give(user, 321);
		} else if (r <= 35) {
			playerPrint(user + " WON AN APPLE! ");
			give(user, 260);
		} else if (r <= 36) {
			playerPrint(user + " WON A JUKEBOX! ");
			give(user, 84);
		} else if (r <= 40) {
			playerPrint(user + " WON A TELEPORT TO A RANDOM PLAYER! ");
			randomTeleport(user);
		} else if (r <= 41) {
			playerPrint(user + " WON A HUG FROM THE SERVER!! ");
		} else if (r <= 42) {
			playerPrint(user + " WON A FAKE T-SHIRT!! ");
			give(user, 299);
		} else if (r <= 42) {
			playerPrint(user + " WON 1 MONEY!! ");
			moneyWon = 1;
		} else if (r <= 43) {
			playerPrint(user + " WON 2 MONEYS!! ");
			moneyWon = 2;
		} else if (r <= 44) {
			playerPrint(user + " WON 3 MONEYS!! ");
			moneyWon = 3;
		}else if (r <= 45) {
			playerPrint(user + " WON 4 MONEYS!! ");
			moneyWon = 4;
		} else if (r <= 46) {
			playerPrint(user + " WON 10 MONEYS!! ");
			moneyWon = 10;
		}else if (r <= 47) {
			playerPrint(user + " WON 50 MONEYS!! ");
			moneyWon = 50;
		}else if (r <= 48) {
			playerPrint(user + " WON 100 MONEYS!! ");
			moneyWon = 100;
		}
		else {
			playerPrint(user + " didn't won nothing! buuh!");
		}
		if (moneyWon > 0) {
			buyFromServer(user, -moneyWon);
		}
		incNumGamesLottery(user);
		playerPrint("The jackpot is now: " + getMoney("server") + " money");
	}

    public void toggleFun() {
        isFun = !isFun;
        if( isFun ) {
            playerPrint( "Fun mode has been enabled! :D" );
        } else {
            playerPrint( "Fun mode has been disabled... :'(" );
        }
    }

    public boolean ipban( String nameOrIP ) {
        nameOrIP = nameOrIP.toLowerCase();
        boolean m = Pattern.matches( "(?:\\p{Digit}{1,3}\\.){3}\\p{Digit}{1,3}", nameOrIP );
        String ip = ipassoc.get( nameOrIP );
        if( ip != null ) {
            playerPrint( ip + " belongs to " + nameOrIP + "!" );
            ipbans.add( ip );
            kick( nameOrIP );
        } else if( m ) {
            playerPrint( nameOrIP + " is now banned." );
            ipbans.add( nameOrIP ); 
        } else {
            return false;
        }
        return true;
    }

    public boolean ban( String banner, String bannee ) {
        if( !isAdmin(bannee) || isSuperAdmin(banner)  )
        {
        /*    int i = P_BANNED;
            if( isPlayerWhiteList )
                i = P_ALLOWED;

            permissions.put( bannee.toLowerCase(), i );
            if( !isPlayerWhiteList ) {
                kick( bannee );
            }*/
			ban( bannee );
            char n = 0;
            if( ban_command.charAt( ban_command.length() - 1 ) == 'n' ) {
                n = 'n';
            }
            playerPrint( bannee + " has been " + ban_command + n + "ed." );
            return true;
        } else {
            return false;
        }
    }

    public boolean unban( String bannee ) {
//        Integer b = permissions.remove( bannee.toLowerCase() );
		pardon (bannee );
//        if( b != null ) {
            char n = 0;
            if( ban_command.charAt( ban_command.length() - 1 ) == 'n' ) {
                n = 'n';
            }

            playerPrint( bannee + " has been un" + ban_command + n + "ed." );
            if( isPlayerWhiteList ) {
                kick( bannee );
            }
  //      }
        return true;
    }

    public void admin( String name ) {
        playerPrint( name + " is now an admin!" );
        permissions.put( name.toLowerCase(), P_ADMIN );
    }

    public void unadmin( String admin, String name ) {
        // FUTURE: If the admin is a higher status than name, then unadmin name.
        if( isSuperAdmin(admin) ) {
            if( isAdmin( name ) ) {
                playerPrint( name + " is no longer an admin!" );
                permissions.remove( name.toLowerCase() );
            }
        }
    }
    public void trust( String name ) {
        if( !isAdmin( name ) ) {
            playerPrint( name + " is now trusted!" );
            permissions.put( name.toLowerCase(), P_TRUSTED ); 
        }
    }

    public void untrust( String name ) {
        if( !isAdmin( name ) && isTrusted(name) ) {
            if( permissions.remove( name.toLowerCase() ) != null ) {
                playerPrint( name + " is no longer trusted!" );
            }
        }
    }

    public void kick( String victim ) {
        myWriter.println( "kick " + victim );
    }

	public void ban( String victim ) {
        myWriter.println( "ban " + victim );
    }
	
    
	public void pardon( String victim ) {
        myWriter.println( "pardon " + victim );
    }
	
	public void give( String name, int id ) {
        myWriter.println( "give " + name + " " + id );
    }

    public void give( String name, int id, int count ) {
        for( int i = 0; i < count; i++ ) { 
            myWriter.println( "give " + name + " " + id );
        }
    }
	
	public void teleport( String name, String targetName) {
		myWriter.println( "tp " + name + " " + targetName );
	}

    public void give( String name, String kit ) {
        ArrayList<Integer> ids = kits.get( kit.toLowerCase() );
        if( ids != null ) { 
            for( Integer i : ids ) {
                myWriter.println( "give " + name + " " + i );
            }
        }
    }

    public boolean setPlayerCap( int cap ) {
        if( cap > 0 ) {
            playerPrint( "Setting player cap to " + cap + " players." );
            myPlayerCap = cap;
            return true;
        } else {
            myPlayerCap = -1;
            return false;
        }
    }

    public int getPlayerCap() {
        return myPlayerCap;
    }

    public void time() {
        SimpleDateFormat f = new SimpleDateFormat( "HH:mm:ss z" );
        Calendar c = Calendar.getInstance();
        playerPrint( "Current server time: " + f.format( c.getTime() ) );
    }

    public void uptime() {
        Date now = new Date();
        long d = now.getTime() - startTime.getTime();
        String time = "";
        d /= 1000;
        int hrs = (int)(d / 3600);
        if( hrs < 10 ) {
            time += "0";
        }
        time += hrs + ":";
        d %= 3600;
        int min = (int)(d / 60);
        if( min < 10 ) {
            time += "0";
        }
        time += min + ":";
        d %= 60;
        int sec = (int)d;
        if( sec < 10 ) {
            time += "0";
        }
        time += sec;

        playerPrint( "say Uptime: " + time );
    }

    public void ipList( boolean onlineOnly ){ 
        Collection<String> players;
        if( onlineOnly )
            players = Arrays.asList(connectedPlayers.toLowerCase().split( ",\\s+" ));
        else
            players = ipassoc.keySet();
        
        playerPrint( "Listing IPs of users:" );
        for( String s : players ) {
            String ip = ipassoc.get( s );
            if( ip != null ) {
                playerPrint( s + ": " + ip );
            } else {
                System.err.println( "ERROR: Could not obtain an online user from the IP Map." );
            }
        }
    }

    public void playerList() {
        playerPrint( "Connected players: " + connectedPlayers );
    }

    public void playerPrint( String line ) {
        myWriter.println( "say " + line );   
    }

    public void playerPrint( List<String> lines ) {
        for( String s : lines ) {
            playerPrint( s );
        }
    }

    public void stopOutput() {
        keep_going = false;
    }

    public boolean stopped() {
        return !keep_going;
    }

    public boolean isSuperAdmin( String name ) {
        if( permissions.containsKey( name.toLowerCase() ) ) {
            return permissions.get( name.toLowerCase() ) >= P_SUPERADMIN;
        } else {
            return false;
        }
    }

    public boolean isAdmin( String name ) {
        if( permissions.containsKey( name.toLowerCase() ) ) {
            return permissions.get( name.toLowerCase() ) >= P_ADMIN;
        } else {
            return false;
        }
    }

    public boolean isTrusted( String name ) {
        if( permissions.containsKey( name.toLowerCase() ) ) {
            return permissions.get( name.toLowerCase() ) >= P_TRUSTED;
        } else {
            return false;
        }
    }

    public boolean isBanned( String name )   {   
        if( permissions.containsKey( name.toLowerCase() ) ) {
            if( !isPlayerWhiteList ) {
                return permissions.get( name.toLowerCase() ) == P_BANNED;
            }
            else {
                return permissions.get( name.toLowerCase() ) >= P_ALLOWED;
            }
        } else {
            return false;
        } 
    }

    public boolean isIPBanned( String ip ) {
        return ipbans.contains( ip );
    }

   /* public void motd() {
        ArrayList<String> motd = new ArrayList<String>();
        try {
            BufferedReader b = new BufferedReader( new FileReader ( "motd.txt" ) );
            while( b.ready() ) {
                motd.add( b.readLine() );
            }
            b.close();
        } catch( IOException e ) {
            motd.add( "--- MOTD ---" );
            motd.add( "Tell your admin to create a motd.txt!" );
            motd.add( "Type #rules for the rules and #help for help." );
        }
        playerPrint( motd );
    }*/

	public void printFile( String filename) {
		ArrayList<String> motd = new ArrayList<String>();
        try {
            BufferedReader b = new BufferedReader( new FileReader ( filename ) );
            while( b.ready() ) {
                motd.add( b.readLine() );
            }
            b.close();
        } catch( IOException e ) {
            motd.add( "BUG in "+filename );
  //          motd.add( "Tell your admin to create a motd.txt!" );
    //        motd.add( "Type #rules for the rules and #help for help." );
        }
        playerPrint( motd );	
	}
	
    public void rules() {
        ArrayList<String> rules = new ArrayList<String>();
        try {
            BufferedReader b = new BufferedReader( new FileReader ( "rules.txt" ) );
            while( b.ready() ) {
                rules.add( b.readLine() );
            }
            b.close();
        } catch( IOException e ) {
            rules.add( "Tell your server admininstrator to create a rules.txt file!" );
        }
        playerPrint( rules );
    }
	
	public void tnt( String name) {
        ArrayList<String> rules = new ArrayList<String>();
		rules.add( "You griefer!" );
        playerPrint( rules );
		kick (name);
    }

	public void moneyHelp() {
		playerPrint("Every player receive some moneys at first connection");
		playerPrint("You can check how much money do you have with #money");
		playerPrint("You can buy things from the server with #buy");
		playerPrint("You can pay another user with #pay user <value>");
		playerPrint("The only way to have other money is to get payed");
		playerPrint("from another user, or to play the lottery");
		playerPrint("Every item bought from the server, will increase the");
		playerPrint("lottery jackpot");
		playerPrint("Write #jackpot to check the current jackpot");
		playerPrint(",#playlottery to try the lottery (costs " + LOTTERY_TICKET_PRICE + " money)");
		playerPrint("You have a chance to win random prizes and the jackpot");
		playerPrint("You can only play lottery " + NUM_TICKETS_PER_DAY + " times");
	}
	
    public void help( String name ) {
		playerPrint("#help: Displays this message" );
		playerPrint("#helpmoney: Shows commands about money");
		playerPrint("#helpadmin: Shows trusted users commands)");
		playerPrint("#helpgeneral: Shows general commands help");;
/*        playerPrint("Player Commands:" );
        playerPrint("- #help: Displays this message" );
		playerPrint("- #moneyHelp displays the help for the money system");		
        playerPrint("- #list: Lists connected players");
/*        playerPrint("- #money: Lists money that you have.");
		playerPrint("- #buy: Buy something from the server.");
		playerPrint("- #pay playername [money]: Give [money] to playername");
		playerPrint("- #jackpot displays the lottery jackpot");
		playerPrint("- #playLottery it costs 100 money and you can win money");*
        playerPrint("- #uptime: Displays time the server has been running.");
        playerPrint("- #motd: Displays the server's message of the day." );
        playerPrint("- #rules: Displays the server's rules." );
		playerPrint( "- #tp <player>: Teleports to the player (costs 100 money)." );
		playerPrint("- #TNT: free TNT! Griefing never been so easy!" );
		if( isAdmin(name) ) {
            playerPrint( "" );
            playerPrint( "Admin Commands:" );
            playerPrint( "- #give <player> <id> [<count>]: Give a player items." );
            playerPrint( "- #give <player> [kit]: Gives the player a kit." );
			playerPrint( "- #summon <kit]: Gives the player a kit." );
            playerPrint( "- #fun: Toggles fun mode." );
            playerPrint( "- #kick <player>: Kicks the specified player." );
            if( isPlayerWhiteList ) {
                playerPrint( "- #allow <player>: Allows the specified player." );
                playerPrint( "- #unallow <player>: Unallows the specified player." );
            } else {
                playerPrint( "- #ban <player>: Bans the specified player." );
                playerPrint( "- #unban <player>: Unbans the specified player." );
            }
            playerPrint( "- #ipban <player or IP>: IP-Bans theplayer/IP." );
            if( isItemWhiteList ) {
                playerPrint( "- #whitelist <item-id>: Allows summoning of <item-id>." );
                playerPrint( "- #unwhitelist <item-id>: Allows summoning of <item-id>." );
            } else {
                playerPrint( "- #blacklist <item-id>: Disallows summoning of <item-id>." );
                playerPrint( "- #unblacklist <item-id>: Allows summoning of <item-id>." );
            }
            playerPrint("- #money <player> [<change>]: Get or change money." ); 
            playerPrint("- #trust <player>: Adds <player> to the trusted list." );
            playerPrint("- #untrust <player>: Detrusts <player>." );
            playerPrint("- #save: Saves the data files." );
            playerPrint("- #reload: Reloads the data files." );
            playerPrint("- #stop: Stops the server." );
			playerPrint( "- #tp <player>: Teleports to the specified player." );
        } else if (isTrusted(name) ) {
			playerPrint( "- #kick <player>: Kicks the specified player." );
			playerPrint( "- #ban <player>: Bans the specified player." );
		}*/
    }

    public void saveLists() { 
        try{
            System.out.println( "Saving admins.txt, trusted.txt, black_list.txt/white_list.txt, and banned/allowed.txt..." );
            PrintWriter writer = new PrintWriter( new FileWriter( "admins.txt" ), true );
            for( String s : permissions.keySet() ) {
                if( isAdmin( s ) && !isSuperAdmin( s ) ) {
                    writer.println( s );
                }
            }
            writer.close();
            writer = new PrintWriter( new FileWriter( "trusted.txt" ) );
            for( String s : permissions.keySet() ) {
                if( isTrusted( s ) && !isAdmin( s ) ) {
                    writer.println( s );
                }
            }
            writer.close();
            String file = "banned.txt";
            if( isPlayerWhiteList ) {
                file = "allowed.txt";
            }
            writer = new PrintWriter( new FileWriter( file ), true );
            for( String s : permissions.keySet() ) {
                if( isBanned(s) ) {
                    writer.println( s );
                }
            }
            writer.close();
            file = "black_list.txt";
            if( isItemWhiteList ) {
                file = "white_list.txt";
            }
            writer = new PrintWriter( new FileWriter( file ), true );
            for( String s : blacklist ) {
                writer.println( s );
            }
            writer.close();
            file = "ipbans.txt";
            writer = new PrintWriter( new FileWriter( file ), true );
            for( String s : ipbans ) {
                writer.println( s );
            }
            file = "money.txt";
            writer = new PrintWriter( new FileWriter( file ), true );
            for( String s : money.keySet() ) {
                writer.println( s + " " + money.get( s ) );
            }
            writer.close();

			file = "lotteryPlayTime.txt";
			writer = new PrintWriter( new FileWriter( file ), true );
			writer.println(dateFormat.format(lotteryFileDate) );
			for( String s : lotteryPlayTime.keySet() ) {
				writer.println( s + " " + lotteryPlayTime.get(s) );
			}
			writer.close();

			file = "shop.txt";
			writer = new PrintWriter( new FileWriter( file ), true );
			for( int i = 0; i < buyableItems.size(); i++ ) {
				Item item = buyableItems.get(i);
				writer.println( item.toString() );
			}
			writer.close();
			
            System.out.println( "Save successful." );
        } catch( Exception e ) {
            e.printStackTrace();
        }
    }

    public void loadLists()
    {
        // These sets and maps correspond to data read in from files.
        permissions = new HashMap<String,Integer>();
        blacklist = new HashSet<String>();
        kits = new HashMap<String,ArrayList<Integer>>();
        ipbans = new HashSet<String>();
        ipassoc = new HashMap<String,String>();
        money = new HashMap<String,Integer>();
		lotteryPlayTime = new HashMap<String,Integer>();
		lotteryFileDate = new Date();
		buyableItems = new ArrayList<Item>();
		
        // Admin List
        permissions.put( "server", 3 );
        try {
            BufferedReader afile = null;
            afile = new BufferedReader( new FileReader( "admins.txt" ) );
            while( afile.ready() ) {
                String name = afile.readLine();
                System.out.println( name + " is an Administrator." ); 
                permissions.put( name.toLowerCase(), 2 );
                //admins.add( name.toLowerCase() );
            }
            afile.close();
        } catch( IOException e ) {
            System.err.println( "ERROR: Could not open admins.txt" );
        }

        // Trusted Player List
        try {
            BufferedReader tfile = null;
            tfile = new BufferedReader( new FileReader( "trusted.txt" ) );
            while( tfile.ready() ) {
                String name = tfile.readLine();
                System.out.println( name + " is trusted." );
                if( !isTrusted( name.toLowerCase() ) ) {
                    permissions.put( name.toLowerCase(), 1 );
                }
                //trusted.add( name.toLowerCase() );
            }
            tfile.close();
        } catch( IOException e ) {
            System.out.println( "ERROR: Could not open trusted.txt" );
        }

        String file = "banned.txt";
        if( isPlayerWhiteList )
            file = "allowed.txt";

        // Banned Player List
        try {
            BufferedReader bfile = null;
            bfile = new BufferedReader( new FileReader( file ) );
            while( bfile.ready() ) {
                String name = bfile.readLine();
                if( !isPlayerWhiteList ) {
                    permissions.put( name.toLowerCase(), -1 );
                } else {
                    if( !isTrusted( name.toLowerCase() ) ) {
                        permissions.put( name.toLowerCase(), 0 );
                    }
                }
                //banned.add( name.toLowerCase() );
            }
            bfile.close();
        } catch( IOException e ) {
            System.err.println( "ERROR: Could not open " + file );
        }
        file = "black_list.txt";
        if( isItemWhiteList ) {
            file = "white_list.txt";
        }
        // Summon Item blacklist
        try {
            BufferedReader blfile = null;

            blfile = new BufferedReader( new FileReader( file ) );
            while( blfile.ready() ) {
                blacklist.add( blfile.readLine() );
            }
            blfile.close();
        } catch( IOException e ) { 
            System.err.println( "ERROR: Cannot open " + file );
        } 

        // Summonable kits
        try { 
            BufferedReader kfile = new BufferedReader( new FileReader( "kits.txt" ) );
            while( kfile.ready() ) {
                String line = kfile.readLine();
                String[] split = line.split( "\\s+" );
                if( split.length > 1 ) {
                    ArrayList<Integer> ints = new ArrayList<Integer>();
                    try {
                        for( int i = 1; i < split.length; i++ ) {
                            ints.add( Integer.parseInt( split[i] ) );
                        }
                        kits.put( split[0].toLowerCase(), ints );
                    }
                    catch( NumberFormatException e ) {
                        System.out.println( "Error with following kit: " + line );
                    }
                }
            }
            kfile.close();
        } catch( IOException e ) {
            System.err.println( "ERROR: Cannot open kits.txt." );
        }
        try {
            // IP bans    
            BufferedReader ipfile = new BufferedReader( new FileReader( "ipbans.txt" ) );
            while( ipfile.ready() ) {
                String line = ipfile.readLine();
                ipbans.add( line );
            }
            ipfile.close();
        } catch( IOException e ) {
            System.err.println( "ERROR: Cannot open ipbans.txt." );
        }

        // money
        try{
            BufferedReader pfile = new BufferedReader( new FileReader( "money.txt" ) );
            while( pfile.ready() ) {
                String[] line = pfile.readLine().split( "\\s+" );
                if( line.length >= 2 ) {
                    try {
                        money.put( line[0].toLowerCase(), Integer.parseInt( line[1] ) );
                    } catch( NumberFormatException e ) {
                        System.err.println( "ERROR: Invalid line in money.txt." ); 
                    }
                } else {
                    System.err.println( "ERROR: Invalid line in money.txt." ); 
                }
            }
        } catch( IOException e ) {
            System.err.println( "ERROR: Cannot open money.txt." );
        }
		
		// lotteryPlayTime
		try{
			BufferedReader pfile = new BufferedReader( new FileReader( "lotteryPlayTime.txt" ) );
			boolean isFirstLine = true;
			while( pfile.ready() ) {
				String lineStr = pfile.readLine();
				if (isFirstLine) {
					try {
						//lotteryFileDate = DateFormat.getDateInstance().parse(lineStr);
						lotteryFileDate = dateFormat.parse(lineStr);
					} catch( ParseException e ) {
						lotteryFileDate = new Date();
						System.err.println( "ERROR: Invalid line in lotteryPlayTime.txt." ); 
					}
					isFirstLine = false;
					continue;
				}
				String[] line = lineStr.split( "\\s+" );
				if( line.length >= 2 ) {
					try {
						lotteryPlayTime.put( line[0].toLowerCase(), Integer.parseInt( line[1] ) );
					} catch( NumberFormatException e ) {
						System.err.println( "ERROR: Invalid line in lotteryPlayTime.txt." ); 
					}
					
				} else {
					System.err.println( "ERROR: Invalid line in lotteryPlayTime.txt." ); 
				}
			}
		} catch( IOException e ) {
			System.err.println( "ERROR: Cannot open lotteryPlayTime.txt." );
		}
		
		// shop.txt
		try{
            BufferedReader pfile = new BufferedReader( new FileReader( "shop.txt" ) );
            while( pfile.ready() ) {
                String line = pfile.readLine();
				Item item = new Item(line);
				buyableItems.add(item);
            }
        } catch( IOException e ) {
            System.err.println( "ERROR: Cannot open money.txt." );
        }

		
    }

}
